<style lang="scss" scoped>
.table-container {
  padding: 20px 20px 0 20px;
  height: 100%;

  display: flex;
  flex-direction: column;

  .table-header {
    margin-bottom: 10px;

    ::v-deep {

      .el-col {
        margin: 2px 0;
      }

      .el-input,
      .el-select {
        width: 100%;
      }
    }
  }

  .table-content {
    flex: 1;
  }

  .table-footer {
    height: 50px;
  }
}
</style>

<template>
  <div class="table-container">
    <div v-if="hasHeader" class="table-header">
      <slot name="header" />
    </div>
    <el-table
      v-loading="loading"
      :data="list"
      class="table-content"
      height="calc(100vh - 170px)"
      border
    >
      <el-table-column
        v-for="column in tableColumnList"
        :key="column.label"
        :label="column.label"
        :fixed="column.fixed"
        :width="column.width"
        :min-width="column.minWidth"
        :max-width="column.maxWidth"
        :align="column.align"
      >
        <template slot-scope="{ row }">

          <!-- JSX -->
          <template v-if="typeof column.render === 'function'">
            <Extend :render="column.render" :params="row" />
          </template>

          <!-- 文本 -->
          <template v-else-if="column.type === undefined || column.type === TABLE_COLUMN_TYPE.TEXT">
            {{ row[column.prop] }}
          </template>

          <!-- 状态 -->
          <template v-else-if="column.type === TABLE_COLUMN_TYPE.SWITCH">
            <el-switch
              v-model="row.status"
              :disabled="row.statusChanging"
              @change="changeStatus(row, column)"
            />
          </template>
        </template>
      </el-table-column>
    </el-table>

    <div class="J-flexBC table-footer">
      <div>
        <slot name="button" />
      </div>
      <Pagination
        :total="pagination.total"
        :page.sync="pagination.page"
        :limit.sync="pagination.limit"
        @pagination="$emit('getList')"
      />
    </div>

    <UpdateDrawer
      v-if="hasUpdateDrawer"
      :visible.sync="drawerVisible"
      :title="updateDrawer.title"
      :type="updateDrawer.type"
      :form="updateDrawer.form"
      :form-item="updateDrawer.formItem"
    />
  </div>
</template>

<script>
import _ from 'lodash'

import Extend from './components/extend.vue'
import UpdateDrawer from './components/updateDrawer.vue'
import Pagination from '@/components/Pagination/index.vue'

import { TABLE_COLUMN_TYPE } from '@/enums/table'

export default {
  components: {
    Extend,
    UpdateDrawer,
    Pagination
  },

  props: {
    list: {
      required: true,
      type: Array
    },

    columns: {
      required: true,
      type: Array
    },

    loading: {
      required: true,
      type: Boolean
    },

    hasHeader: {
      type: Boolean,
      default: false
    },

    hasUpdateDrawer: {
      type: Boolean,
      default: false
    },

    updateDrawer: {
      type: Object,
      default: () => ({})
    },

    pagination: {
      required: true,
      type: Object
    }
  },

  data() {
    return {
      /**
       * @type {import('@/types/table').TABLE_OPTIONS[]}
       */
      tableColumnList: [],

      drawerVisible: false,

      TABLE_COLUMN_TYPE
    }
  },

  watch: {
    'updateDrawer.visible'(val) {
      this.drawerVisible = val
    }
  },

  created() {
    /**
     * @type {import('@/types/table').TABLE_OPTIONS[]}
     */
    this.tableColumnList = this.columns

    TABLE_COLUMN_TYPE
  },

  methods: {
    changeStatus(row, column) {
      if (!_.isFunction(column.changeStatus)) {
        throw new Error('changeStatus 接口不存在')
      }

      if (_.isEmpty(column.changeStatusParams)) {
        throw new Error('changeStatusParams 为空')
      }

      const params = _.reduce(column.changeStatusParams, (result, key) => {
        const params = { [key]: row[key] }

        result = _.merge(result, params)

        return result
      }, {
        status: row.status
      })

      column.changeStatus(params).then(() => {
        this.$message.success('修改状态成功')
      })
    }
  }
}
</script>
